package br.edu.ufcg.greengrid.workload;

import java.io.FileWriter;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;

public class GWADemandClassificationParser {

	private static final long RUNTIME_LIMIT = 2 * 3600; //seconds
	private static final long NPROC_LIMIT = 1;
	
	private final int numClasses;
	private final String outputFilePrefix;
	private final String gwaTraceFile;
	private final int jobsPerWindow;
	private final double percentilToIgnore;

	private DescriptiveStatistics durationStats;

	public GWADemandClassificationParser(String gwaTraceSqliteFile,
			int numClasses, int jobsPerWindow, String outputFilePrefix,
			double percentilToIgnore) throws IOException {
		this.numClasses = numClasses;
		this.jobsPerWindow = jobsPerWindow;
		this.outputFilePrefix = outputFilePrefix;
		this.gwaTraceFile = gwaTraceSqliteFile;
		this.percentilToIgnore = percentilToIgnore;
		this.durationStats = new DescriptiveStatistics();
	}

	private List<WorkloadWindowInfo> createWindowInfoList() throws SQLException, IOException {

		GWAWorkload parser = new GWAWorkload(gwaTraceFile);

		parser.start();
		
		FileWriter statsWriter = new FileWriter(outputFilePrefix + "_stats.txt");

		List<WorkloadWindowInfo> windowList = new ArrayList<WorkloadWindowInfo>();

		Job job = readJob(parser);

		while (job != null) {

			long aggregateRuntime = 0;
			long numJobs = 0;

			long startTime = job.getSubmitTime();
			long endTime = -1;

			for (int i = 0; i < jobsPerWindow && job != null; i++) {
				aggregateRuntime += job.getRunTime();
				numJobs++;
				endTime = job.getSubmitTime();
				job = readJob(parser);
			}

			WorkloadWindowInfo windowInfo = new WorkloadWindowInfo(startTime,
					endTime, aggregateRuntime, numJobs);

			durationStats.addValue(windowInfo.getDuration());

			windowList.add(windowInfo);
			statsWriter.write(windowList.size() + "\t"
					+ windowInfo.getDuration() + "\t"
					+ windowInfo.getAggregateRuntime() + "\n");
		}
		
		statsWriter.close();

		parser.close();

		double highestDuration = durationStats.getPercentile(percentilToIgnore);
		double lowestDuration = durationStats.getMin();

		double demandInterval = (highestDuration - lowestDuration + 2)
				/ numClasses;

		for (WorkloadWindowInfo workloadWindowInfo : windowList) {
			if (workloadWindowInfo.getDuration() <= highestDuration) {
				int index = (int) Math.ceil((workloadWindowInfo.getDuration()
						- lowestDuration + 1)
						/ demandInterval);
				workloadWindowInfo.setDemandClass(index);
			}
		}

		return windowList;
	}

	private Job readJob(GWAWorkload parser) {
		Job job = null;

		while ((job = parser.poll()) != null && (job.getRunTime() > RUNTIME_LIMIT || job.getNProc() > NPROC_LIMIT));
	
		return job;
	}

	public void parse() throws SQLException, IOException {

		List<WorkloadWindowInfo> windowInfoList = createWindowInfoList();

		GWAWorkload parser = new GWAWorkload(gwaTraceFile);

		parser.start();

		Job job;

		int windowCount = 0;

		job = readJob(parser);

		while (job != null) {

			WorkloadWindowInfo windowInfo = windowInfoList.get(windowCount);
			long durationInMinutes = windowInfo.getDuration() / 60;
			long averageRuntime = windowInfo.getAggregateRuntime()
					/ jobsPerWindow;
			FileWriter writer = new FileWriter(outputFilePrefix + "_dc"
					+ windowInfo.getDemandClass() + "_w" + windowCount + "_wd"
					+ durationInMinutes + "_rt" + averageRuntime + ".txt");

			while (job != null
					&& job.getSubmitTime() < windowInfo.getStartTime()) {
				job = readJob(parser);
			}

			for (int i = 0; i < jobsPerWindow && job != null; i++) {
				writer.write(job.getSubmitTime() + "\t" + job.getRunTime()
						+ "\n");
				job = readJob(parser);
			}

			writer.close();
			windowCount++;
		}
	}

	public static void main(String[] args) throws IOException, SQLException {

		String argGwaTraceSqliteFile = "/media/data/workloads/gwa-t3/anon_jobs.db3";
		int argNumClasses = 2;
		int argJobsPerWindow = 5000;
		String argOutputFilePrefix = "t3";
		int argPercentilToIgnore = 75;

		if (args.length >= 5) {
			argGwaTraceSqliteFile = args[0];
			argNumClasses = Integer.valueOf(args[1]);
			argJobsPerWindow = Integer.valueOf(args[2]);
			argOutputFilePrefix = args[3];
			argPercentilToIgnore = Integer.valueOf(args[4]);
		} else {
			System.err
					.println("Invalid arguments. Usage: java br.edu.ufcg.greengrid.workload.GWADemandClassificationParser <gwaTraceSqliteFile> <numCategories> <jobsPerWindow> <outputFilesPrefix> <PercentilToIgnore>");
			System.exit(1);
		}

		GWADemandClassificationParser parser = new GWADemandClassificationParser(
				argGwaTraceSqliteFile, argNumClasses, argJobsPerWindow,
				argOutputFilePrefix, argPercentilToIgnore);
		parser.parse();
	}

}
